package com.agent.logaspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.agent.annotation.WebLog;
import com.agent.handler.WebLogHandler;
import com.agent.logbean.WebLogBean;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by fangjicai on 2020/5/31.
 * 定义日志切面
 */
@Aspect
@Order(10)
@Component
public class WebLogAspect {
    private static final Logger logger= LoggerFactory.getLogger(WebLogAspect.class);
    private ThreadLocal<Long> startTimeThreadLocal=new ThreadLocal<>();
    private ThreadLocal<WebLogBean> webLogBeanThreadLocal=new ThreadLocal<>();
    private ThreadLocal<Boolean> isPersistentThreadLocal=new ThreadLocal<>();
    public static final String TYPE_NAME_SERVLET="org.springframework.security.web.servletapi.HttpServlet3RequestFactory$Servlet3SecurityContextHolderAwareRequestWrapper";
    public static final String UNDERTOW_SERVLET_TYPE_NAME="io.undertow.servlet.spec.HttpServletRequestImpl";
    public static final String APACHE_REQUEST_FACADE="org.apache.catalina.connector.RequestFacade";
    public static final String MOCK_HTTP_SERVLET_REQUEST="org.springframework.mock.web.MockHttpServletRequest";

    /**
     * 日志处理类
     */
    @Autowired
    private WebLogHandler webLogHandler;

    // 切面的范围为前面定义的注解
    @Pointcut("@annotation(com.agent.annotation.WebLog)")
    public void start() {}

    @Before("start()")
    public void before(JoinPoint joinPoint) {
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        WebLogBean webLogBean=new WebLogBean();
        webLogBean.setBrowserInfo(request.getHeader("User-Agent"));
        webLogBean.setRequestURL(request.getRequestURL().toString());
        webLogBean.setHttpMethod(request.getMethod());
        webLogBean.setRequestIP(request.getRemoteAddr());
        //获取方法输入参数
        Object[] args=joinPoint.getArgs();
        List<Object> paramList=new ArrayList<>();
        if (args != null && args.length > 0) {
            for (int i=0; i<args.length ;i++) {
                if (args[i] != null) {
                    String typeName = args[i].getClass().getTypeName();
                    if (logger.isInfoEnabled()) {
                        logger.info(" request Parameter TypeName is "+typeName);
                    }
                    if (TYPE_NAME_SERVLET.equals(typeName) || UNDERTOW_SERVLET_TYPE_NAME.equals(typeName) ||
                            APACHE_REQUEST_FACADE.equals(typeName) || MOCK_HTTP_SERVLET_REQUEST.equals(typeName)) {
                        continue;
                    }
                    paramList.add(args[i]);
                }
            }
            String jsonParam= JSON.toJSONString(paramList, SerializerFeature.WriteNullListAsEmpty);
            webLogBean.setRequestParam(jsonParam);
        }
        webLogBean.setOperateClassMethod(joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
        MethodSignature methodSignature=(MethodSignature)joinPoint.getSignature();
        Method method=methodSignature.getMethod();
        //获取注解中的value值
        WebLog webLog=method.getAnnotation(WebLog.class);
        webLogBean.setOperateDesc(webLog.value());
        if (logger.isInfoEnabled()) {
            logger.info("请求参数：["+webLogBean.toString()+"]");
        }
        startTimeThreadLocal.set(System.currentTimeMillis());
        isPersistentThreadLocal.set(webLog.persistent());
        //将日志对象存储到ThreadLocal对象下，方便对象传递
        webLogBeanThreadLocal.set(webLogBean);
    }

    @AfterReturning(pointcut ="start()",returning = "object")
    public void afterReturning(Object object) {
        if (webLogBeanThreadLocal.get()!= null) {
            WebLogBean webLogBean = webLogBeanThreadLocal.get();
            if (startTimeThreadLocal.get() != null) {
                long startTime = startTimeThreadLocal.get();
                webLogBean.setConsumeTime(System.currentTimeMillis() - startTime);
            }
            webLogBean.setResponseResult(JSONObject.toJSONString(object));
            webLogBean.setOperateTime(new Date());
            if (logger.isInfoEnabled()) {
                logger.info("请求处理结束,参数：["+JSON.toJSONString(webLogBean)+"]");
            }
            Boolean persistentFlag=null;
            if (isPersistentThreadLocal.get()!= null) {
                persistentFlag=isPersistentThreadLocal.get();
            }

            try {
                webLogHandler.processLog(webLogBean, persistentFlag);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        startTimeThreadLocal.remove();
        webLogBeanThreadLocal.remove();
        isPersistentThreadLocal.remove();
    }

    @AfterThrowing(pointcut = "start()",throwing = "throwable")
    public void afterThrowing(Throwable throwable) {
        logger.error("业务处理发生异常",throwable);
        if (logger.isInfoEnabled()) {
            logger.info("业务处理发生异常"+throwable.getMessage());
        }
        if (webLogBeanThreadLocal.get() != null) {
            WebLogBean webLogBean = webLogBeanThreadLocal.get();
            if (startTimeThreadLocal.get()!=null) {
                long startTime = startTimeThreadLocal.get();
                webLogBean.setConsumeTime(System.currentTimeMillis() - startTime);
            }
            webLogBean.setExceptionMsg(throwable.getMessage());
            webLogBean.setOperateTime(new Date());
            if (logger.isInfoEnabled()) {
                logger.info("请求处理异常,参数：["+JSON.toJSONString(webLogBean)+"]");
            }
            boolean persistentFlag=false;
            if (isPersistentThreadLocal.get()!= null) {
                persistentFlag=isPersistentThreadLocal.get();
            }
            try {
                webLogHandler.processLog(webLogBean,persistentFlag);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        startTimeThreadLocal.remove();
        webLogBeanThreadLocal.remove();
        isPersistentThreadLocal.remove();
    }
}
